/*
 * calculation_server_test.cpp
 *
 *  Created on: 21/06/2011
 *      Author: Yotam and Gilaad
 */

#include "../calculation_server.h"
#include "mtmtest.h"
#include "../matrix.h"
#include <stdarg.h>

Matrix initMatrix( int rows, int columns, ... ) {
	Matrix result( rows, columns );

	va_list vl;
	va_start( vl, columns );

	for( int r = 1; r <= rows; ++r ) {
		for( int c = 1; c <= columns; ++c ) {
			double cell = va_arg(vl,double);
			result(r, c) = cell;
		}
	}
	va_end( vl );
	return result;
}

bool testAddJob(){
	CalculationServer server;
	Matrix A=initMatrix(2,2, 1, 2, 3, 4);
	Matrix B=initMatrix(2,2, 1, 5, 6, 8);
	int job1,job2,job3,job4,job5,job6;
	ASSERT_NO_THROW(job1 = server.addJob
							(CalculationServer::SOLVE_EQUATION_SYSTEM,50,A,B));
	ASSERT_NO_THROW(job2 = server.addJob(CalculationServer::SIMILARITY,30,A,B));
	ASSERT_NO_THROW(job3 = server.addJob(CalculationServer::POLYNOMIAL,20,A,B));
	ASSERT_EQUALS(job1!=job2, true);
	ASSERT_EQUALS(job2!=job3, true);
	ASSERT_EQUALS(job1!=job3, true);
	ASSERT_THROW(CalculationServer::InvalidPriority,
	server.addJob(CalculationServer::SIMILARITY,-1,A,B));
	ASSERT_THROW(CalculationServer::InvalidPriority,
	server.addJob(CalculationServer::POLYNOMIAL,101,A,B));
	ASSERT_THROW(CalculationServer::InvalidPriority,
	server.addJob(CalculationServer::SOLVE_EQUATION_SYSTEM,200,A,B));
	ASSERT_EQUALS(job1,server.nextJob());
	ASSERT_NO_THROW(job4 = server.addJob
	(CalculationServer::SOLVE_EQUATION_SYSTEM,51,A,B));
	ASSERT_EQUALS(job4,server.nextJob());
	ASSERT_NO_THROW(job5 = server.addJob(CalculationServer::POLYNOMIAL,50,A,B));
	ASSERT_EQUALS(job4,server.nextJob());
	ASSERT_NO_THROW(job6 = server.addJob
	(CalculationServer::SOLVE_EQUATION_SYSTEM,51,A,B));
	ASSERT_EQUALS(job4,server.nextJob());

	return true;
}
bool testRemoveJob(){
	CalculationServer server;
    Matrix A = initMatrix(2,2, 1.0, 1.0, 1.0, 1.0);
    Matrix B = initMatrix(4,1, 2.0, 0.0, 1.0, -1.0);
    ASSERT_THROW(CalculationServer::JobNotFound, server.removeJob( -1));
    ASSERT_THROW(CalculationServer::JobNotFound, server.removeJob( 15));
    int id1 = server.addJob(CalculationServer::POLYNOMIAL, 50, A, B);
    int id2 = server.addJob(CalculationServer::SOLVE_EQUATION_SYSTEM, 50,
    												Matrix::createUnit(4), B);
    int id3 = server.addJob(CalculationServer::SIMILARITY, 80, A, A);
    // The jobs order should be: id3 -> id1 -> id2

    ASSERT_NO_THROW(server.removeJob(id2));
    ASSERT_EQUALS(server.totalJobs(),2);
    ASSERT_THROW(CalculationServer::JobNotFound, server.removeJob(id2));
    ASSERT_EQUALS(id3, server.nextJob());
    ASSERT_NO_THROW(server.removeJob(id3));
    ASSERT_EQUALS(server.totalJobs(),1);
    ASSERT_THROW(CalculationServer::JobNotFound, server.removeJob(id3));
    ASSERT_EQUALS(id1, server.nextJob());
    ASSERT_NO_THROW(server.removeJob(id1));
    ASSERT_EQUALS(server.totalJobs(),0);
    ASSERT_THROW(CalculationServer::JobNotFound, server.nextJob());

    return true;
}
bool testChangePriority(){
    CalculationServer server;
    Matrix A = initMatrix(2,2, 1.0, 1.0, 1.0, 0.0);
    Matrix B = initMatrix(4,1, 2.0, 2.0, 1.0, -1.0);
    int id1 = server.addJob(CalculationServer::POLYNOMIAL, 50, A, B);
    int id2 = server.addJob(CalculationServer::SOLVE_EQUATION_SYSTEM, 50,
    												Matrix::createUnit(4), B);
    int id3 = server.addJob(CalculationServer::SIMILARITY, 80, A, A);
    // The jobs order should be: id3 -> id1 -> id2

    ASSERT_EQUALS(id3, server.nextJob());
    ASSERT_THROW(CalculationServer::InvalidPriority,
    									server.changePriority(id2, -10));
    ASSERT_EQUALS(id3, server.nextJob());
    ASSERT_NO_THROW(server.changePriority(id3,30));
    // The jobs order should be: id1 -> id2 -> id3
    ASSERT_EQUALS(id1, server.nextJob());
    ASSERT_NO_THROW(server.changePriority(id2,100));
    // The jobs order should be: id2 -> id1 -> id3
    ASSERT_EQUALS(id2, server.nextJob());
    ASSERT_NO_THROW(server.changePriority(id3,100));
    // The jobs order should be: id2 -> id3 -> id1
    ASSERT_EQUALS(id2, server.nextJob());
    ASSERT_NO_THROW(server.changePriority(id1,100));
    // The jobs order should be: id1 -> id2 -> id3
    ASSERT_EQUALS(id1, server.nextJob());

    server.execute();
    ASSERT_EQUALS(id2, server.nextJob());
    server.execute();
    ASSERT_EQUALS(id3, server.nextJob());
    ASSERT_THROW(CalculationServer::JobNotFound,
    										server.changePriority(1000,100));
    ASSERT_THROW(CalculationServer::InvalidPriority,
    										server.changePriority(id3,-1));
    ASSERT_THROW(CalculationServer::JobNotFound,server.changePriority(150,-1));
    ASSERT_NO_THROW(server.changePriority(id3,0));

    return true;
}
bool testExecute(){
    CalculationServer server;
    Matrix A = initMatrix(2,2, 1.0, 1.0, 1.0, 0.0);
    Matrix B = initMatrix(4,1, 2.0, 0.0, 1.0, -1.0);
    ASSERT_THROW(CalculationServer::JobNotFound, server.execute());
    int id1 = server.addJob(CalculationServer::POLYNOMIAL, 50, A, B);
    int id2 = server.addJob(CalculationServer::SOLVE_EQUATION_SYSTEM,
    											50, Matrix::createUnit(4), B);
    int id3 = server.addJob(CalculationServer::SIMILARITY, 80, A, A);
    // The jobs order should be: id3 -> id1 -> id2
    ASSERT_NO_THROW(server.execute());
    ASSERT_EQUALS(server.totalJobs(),2);
    ASSERT_THROW(CalculationServer::JobNotFound, server.removeJob(id3));
    ASSERT_EQUALS(id1, server.nextJob());
    // The jobs order should be: id1 -> id2
    Matrix resultIdNum1 = server.execute();
    Matrix C = initMatrix(2,2, 1.0, -1.0, -1.0, 2.0);
    ASSERT_EQUALS(C, resultIdNum1);
    ASSERT_EQUALS(server.totalJobs(),1); // id2
    ASSERT_THROW(CalculationServer::JobNotFound, server.removeJob(id1));
    ASSERT_EQUALS(id2, server.nextJob());
    // The jobs order should be: id2
    int id4 = server.addJob(CalculationServer::SIMILARITY, 30, A, A);
    // The jobs order should be: id2 -> id4
    server.changePriority(id2,20);
    // The jobs order should be: id4 -> id2
    ASSERT_EQUALS(server.totalJobs(),2);
    ASSERT_THROW(CalculationServer::JobNotFound, server.removeJob(id3));
    ASSERT_NO_THROW(server.execute());
    ASSERT_NO_THROW(server.execute());
    ASSERT_EQUALS(server.totalJobs(),0);
    ASSERT_THROW(CalculationServer::JobNotFound, server.removeJob(id4));
    ASSERT_THROW(CalculationServer::JobNotFound, server.execute());

    return true;
}
bool testNextJob(){
    CalculationServer server;
    Matrix A = initMatrix(2,2, 1.0, 1.0, 1.0, 0.0);
    Matrix B = initMatrix(4,1, 2.0, 0.0, 1.0, -1.0);
    ASSERT_THROW(CalculationServer::JobNotFound,server.nextJob());
    int id1 = server.addJob(CalculationServer::POLYNOMIAL, 50, A, B);
    ASSERT_EQUALS(id1,server.nextJob());
    int id2 = server.addJob(CalculationServer::SOLVE_EQUATION_SYSTEM, 50,
    												Matrix::createUnit(4), B);
    ASSERT_EQUALS(id1,server.nextJob());
    int id3 = server.addJob(CalculationServer::SIMILARITY, 80, A, A);
    ASSERT_EQUALS(id3,server.nextJob());
    // The jobs order should be: id3 -> id1 -> id2
    server.execute();
    ASSERT_EQUALS(id1,server.nextJob());
    //The jobs order should be: id1 -> id2
    ASSERT_NO_THROW(server.changePriority(id1,10));
    ASSERT_EQUALS(id2,server.nextJob());
    ASSERT_NO_THROW(server.removeJob(id2));
    ASSERT_EQUALS(id1,server.nextJob());
    ASSERT_NO_THROW(server.execute());
    ASSERT_THROW(CalculationServer::JobNotFound,server.nextJob());

    return true;
}
bool testTotalJobs(){
    CalculationServer server;
    Matrix A = initMatrix(2,2, 1.0, 1.0, 1.0, 0.0);
    Matrix B = initMatrix(4,1, 2.0, 0.0, 1.0, -1.0);
    ASSERT_EQUALS(0, server.totalJobs());
    server.addJob(CalculationServer::POLYNOMIAL, 50, A, B);
    ASSERT_EQUALS(1, server.totalJobs());
    int id1 = server.addJob(CalculationServer::SOLVE_EQUATION_SYSTEM, 50,
    												Matrix::createUnit(4), B);
    ASSERT_EQUALS(2, server.totalJobs());
    server.addJob(CalculationServer::SIMILARITY, 80, A, A);
    ASSERT_EQUALS(3, server.totalJobs());
    ASSERT_NO_THROW(server.removeJob(id1));
    ASSERT_EQUALS(2, server.totalJobs());
    ASSERT_NO_THROW(server.execute());
    ASSERT_EQUALS(1, server.totalJobs());
    ASSERT_NO_THROW(server.execute());
    ASSERT_EQUALS(0, server.totalJobs());

    return true;
}

int main(){
	RUN_TEST(testAddJob);
	RUN_TEST(testRemoveJob);
	RUN_TEST(testChangePriority);
	RUN_TEST(testExecute);
	RUN_TEST(testNextJob);
	RUN_TEST(testTotalJobs);

	return 0;
}
